package com.aiti.lulian.pay.strategy.impl;

import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import com.aiti.base.core.utils.stringUtil.StringUtil;

import com.aiti.lulian.pay.OrderStatusEnum;
import com.aiti.lulian.pay.config.AliPayProperties;
import com.aiti.lulian.pay.model.AliPayPreOrderData;
import com.aiti.lulian.pay.model.CardVipRecord;
import com.aiti.lulian.pay.model.PayInfo;
import com.alibaba.druid.util.StringUtils;
import com.alibaba.fastjson.JSONObject;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.domain.AlipayTradePagePayModel;
import com.alipay.api.domain.AlipayTradeQueryModel;
import com.alipay.api.internal.util.AlipaySignature;
import com.alipay.api.request.AlipayTradePagePayRequest;
import com.alipay.api.request.AlipayTradePrecreateRequest;
import com.alipay.api.request.AlipayTradeQueryRequest;
import com.alipay.api.response.AlipayTradePagePayResponse;
import com.alipay.api.response.AlipayTradePrecreateResponse;
import com.alipay.api.response.AlipayTradeQueryResponse;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

/**
 * 支付宝的支付策略类
 */
@Slf4j
@Service("aliPayStrategy")
public class AliPayStrategy extends AbstractPayStrategy {

    private static final String PAY_TOKEN_PRE = "ali:pay:token:%s";

    @Autowired
    private AlipayClient alipayClient;

    @Autowired
    private RedissonClient redissonClient;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public AliPayPreOrderData genPayQrCode(PayInfo payInfo) {
//        Long result = redisTemplate.execute(new DefaultRedisScript<>(LUA_SCRIPT, Long.class), Arrays.asList(String.format(PAY_TOKEN_PRE, payInfo.getUserId())), payInfo.getToken());
//        if(result == 0L){
//            throw new RuntimeException("您已下过单或者是在当前页面停留时间较长，请重新刷新页面后在支付");
//        }
        //生成用户相关的订单信息
        CardVipRecord order = createOrder(payInfo);
        // 构造请求参数以调用接口
        AlipayTradePagePayRequest request = new AlipayTradePagePayRequest();
//        request.setNotifyUrl("http://2unvzn.natappfree.cc/cy-lulian-global/v1/pay/success");
        request.setNotifyUrl("https://yunzhanting.org.cn/cy-lulian-global/v1/pay/success");
        request.setReturnUrl("https://yunzhanting.org.cn");
        AlipayTradePagePayModel model = new AlipayTradePagePayModel();
        // 设置商户订单号
        model.setOutTradeNo(order.getBaseId());
        //将单位为分的金额转成元为单位的
        String amountYuan = convert(payInfo.getPayAmount());
        // 设置订单总金额
        model.setTotalAmount(amountYuan);
        // 设置订单标题
        model.setSubject(payInfo.getVipName());
        model.setProductCode("FAST_INSTANT_TRADE_PAY");
        // 设置商户自定义二维码宽度
        model.setQrcodeWidth(100L);
        request.setBizModel(model);

        try{
            AlipayTradePagePayResponse response = alipayClient.pageExecute(request, "POST");
            String pageRedirectionData = response.getBody();
            if (response.isSuccess()) {
                return AliPayPreOrderData.builder()
                        .js(pageRedirectionData)
                        .tradeNo(order.getBaseId())
                        .build();
            }
        }catch (AlipayApiException e){
            e.printStackTrace();
        }
        return new AliPayPreOrderData();
    }

    /**
     * 阿里支付成功的回调
     *
     * @param paramsMap 阿里传来的参数
     * @return
     */
    @Override
    public String aliCallBack(Map<String, String> paramsMap) {
        String result = "failure";
        log.warn("支付宝回调");
        String tradeNo = paramsMap.get("trade_no");
        RLock rLock = redissonClient.getLock("pay:ali:lock:" + tradeNo);
        rLock.lock();
        try {
            //1.先进行验签，用来保证当前接口是被支付宝回调的
            boolean signVerified = AlipaySignature.rsaCheckV1(paramsMap,
                    AliPayProperties.aliPublicKey
                    , "UTF8", "RSA2");
            if (!signVerified) {
                log.warn("支付宝返回签名效验失败。");
                return result;
            }

            //2.进行商户订单号的校验。
            String outTradeNo = paramsMap.get("out_trade_no");
            CardVipRecord outTradeNoOrderData = service.getOne(new QueryWrapper<CardVipRecord>().eq("base_id", outTradeNo));
            if (outTradeNoOrderData == null) {
                log.warn(String.format("没有找到该商户号的记录:%s", outTradeNo));
                return result;
            }

            //效验支付的金额
            String totalAmount = paramsMap.get("total_amount");
            String vipAmountYuan = convert(outTradeNoOrderData.getPayAmount());
            if (!StringUtils.equals(totalAmount, vipAmountYuan)) {
                log.warn("支付宝返回的支付金额与订单金额不同，效验失败");
                return result;
            }

            //效验是否是商户本身
            String sellerId = paramsMap.get("seller_id");
            if (!StringUtils.equals(AliPayProperties.sellerId, sellerId)) {
                log.warn("商户效验失败");
                return result;
            }
            //效验 APPID
            String appId = paramsMap.get("app_id");
            if (!StringUtils.equals(AliPayProperties.appId, appId)) {
                log.warn("APPID效验失败");
                return result;
            }

            //如果当前订单的状态是已支付，就直接返回成功
            //这里的原因是支付宝回调可能会存在并发回调
            if (StringUtil.equals(outTradeNoOrderData.getOrderStatus(), OrderStatusEnum.PAID.getStatus())) {
                return "success";
            }

            //数据幂等性,这里修改订单状态之前需要判断下订单的状态是不是未支付或者是超时未支付。
            if (!(StringUtils.equals(outTradeNoOrderData.getOrderStatus(), OrderStatusEnum.UNPAID.getStatus()) || StringUtils.equals(outTradeNoOrderData.getOrderStatus(), OrderStatusEnum.LONGTERMUNPAID.getStatus()))) {
                return result;
            }
            //交易的状态
            String tradeStatus = paramsMap.get("trade_status");
            //只有当状态为TRADE_SUCCESS或者是TRADE_FINISHED表示支付成功；
            if ("TRADE_SUCCESS".equalsIgnoreCase(tradeStatus) || "TRADE_FINISHED".equalsIgnoreCase(tradeStatus)) {
                outTradeNoOrderData.setOrderStatus(OrderStatusEnum.PAID.getStatus());
                outTradeNoOrderData.setPayTime(DateUtil.parse(paramsMap.get("gmt_payment")));
                outTradeNoOrderData.setTradeNo(paramsMap.get("trade_no"));
                service.update(outTradeNoOrderData, new UpdateWrapper<CardVipRecord>().eq("base_id", outTradeNoOrderData.getBaseId()));

                //获取到生成订单的时候存入数据库中的用户所对应的企业Id
                String enterpriseId = outTradeNoOrderData.getEnterpriseId();
                if(StringUtil.isNotBlank(enterpriseId)){
                    dataMigration(enterpriseId,outTradeNoOrderData.getVipLevel(),outTradeNoOrderData.getUserId(),2, tradeNo);
                }

                log.info("数据效验成功");
                result = "success";
            }
        }catch (Exception e){
           log.error("报错：{}",e.getMessage());
        }
        return result;
    }

    /**
     * 查询订单状态
     *
     * @param orderId 商户定单号
     * @return
     */
    @Override
    public String queryOrderState(String orderId) {
        // 构造请求参数以调用接口
        AlipayTradeQueryRequest request = new AlipayTradeQueryRequest();
        AlipayTradeQueryModel model = new AlipayTradeQueryModel();

        // 设置订单支付时传入的商户订单号
        model.setOutTradeNo(orderId);
        request.setBizModel(model);
        try{
            AlipayTradeQueryResponse response = alipayClient.execute(request);
            System.out.println(response.getBody());
            if (response.isSuccess()) {
                JSONObject jsonObject = JSONObject.parseObject(response.getBody());
                JSONObject aliapyTradeQueryResponse = jsonObject.getJSONObject("alipay_trade_query_response");
                String o = aliapyTradeQueryResponse.getString("trade_status");
               if(StringUtil.equals(o,"TRADE_SUCCESS")){
                    return "success";
               }else if(StringUtil.equals(o,"WAIT_BUYER_PAY")){
                    return "wait";
               }
                return "fail";
            } else if(StringUtil.equals(response.getCode(),"40004")){
                return "notfound";
            }else{
                return "fail";
            }
        } catch (AlipayApiException e) {
            e.printStackTrace();
            return "fail";
        }
    }
}
